/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package villapancha2011;

import java.util.List;
import java.util.LinkedList;
import java.util.Random;

import org.javahispano.javacup.modelo.*;

/**
 *
 * @author Jorgeao
 */
public class Pase extends VillaPanchaBase {

    public Pase(TacticaVillaPancha2011 t) {
        super(t);
    }

    double calcularFuerzaPase(Grosso origen, Grosso destino, Posicion destinoPos, double anguloVertical) {
        double av = anguloVertical * Math.PI / 180d;
        //velocidad
        double fuerza = 0.05;
        double r = 0, z = 0, distancia = 0;
        do {
            double vel = Constantes.getVelocidadRemate(situacionPartido().getRemateJugador(origen.ordinal())) * fuerza;
            //direccion;
            double dz = vel * Math.sin(av);
            double dr = vel * Math.cos(av);
            AbstractTrayectoria trayectoria = new TrayectoriaAire(dr, dz, 0, 0);
            //coordenadas
           // for (int tiempo = 59; tiempo < 60; tiempo++) {
                int tiempo =(int) (Constantes.REMATE_VELOCIDAD_MIN * 30d);
                r = trayectoria.getX((double) tiempo / 60d) * Constantes.AMPLIFICA_VEL_TRAYECTORIA;
                z = trayectoria.getY((double) tiempo / 60d) * Constantes.AMPLIFICA_VEL_TRAYECTORIA;

                boolean alcanceJugador = z < Constantes.ALTURA_CONTROL_BALON;

                distancia = situacionPartido().misJugadores()[origen.ordinal()].distancia(destinoPos);
                if (r > distancia && alcanceJugador) {
                    System.out.println("====================================================");
                    System.out.println("Fuerza: " + fuerza + "; distancia: " + distancia);
                    System.out.println("r: " + r + "; z: " + z);
                    System.out.println("Destino: " + (destino.ordinal() + 1));
                    System.out.println("====================================================");
                    return fuerza;
                }
            //}
            fuerza += 0.005;
        } while (fuerza <= 1.1); // Pongo a proposito un poco mas de 1
        System.out.println("*************** NO LLEGAA ****************");
        System.out.println("Fuerza: " + fuerza + "; distancia: " + distancia);
                    System.out.println("r: " + r + "; z: " + z);
                    System.out.println("Destino: " + (destino.ordinal() + 1));
        System.out.println("*********************************************");
        return fuerza;
    }


    // Metodos auxiliares para pase
    boolean esPasePorBajoSeguro(Posicion desde, Grosso receptor) {
        for (int i=0; i<11; ++i)
        {

            Posicion rival = situacionPartido().rivales()[i];

            Posicion posTirador = desde;
            Posicion posReceptor = situacionPartido().misJugadores()[receptor.ordinal()];


            double deltaX = posReceptor.getX() - posTirador.getX();
            double deltaY = posReceptor.getY() - posTirador.getY();

            double rReceptor = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
            double aReceptor = Math.asin(deltaY / rReceptor);

            if (deltaX < 0)
            {
                rReceptor = -rReceptor;
            }

            double errorTirador = 0;
            for (int j : situacionPartido().puedenRematar())
            {
                double errorTiradorTemp = Constantes.getErrorAngular(situacionPartido().getErrorJugador(j));
                if (errorTiradorTemp > errorTirador)
                {
                    errorTirador = errorTiradorTemp;
                }
            }

            errorTirador = ((errorTirador * 90d) * Math.PI) / 180d;

            Posicion posReceptorError1 = posTirador.moverAngulo(aReceptor + errorTirador * 0.8, rReceptor); //1.5
            Posicion posReceptorError2 = posTirador.moverAngulo(aReceptor - errorTirador * 0.8, rReceptor);

             double a = -(posTirador.getY() - posReceptorError1.getY())
                    / (posTirador.getX() - posReceptorError1.getX());
            double c = a * posTirador.getX() - posTirador.getY();

            double distPeligro1 = Math.abs(a * rival.getX() + rival.getY() + c)
                    / Math.sqrt(a * a + 1);

            double a2 = -(posTirador.getY() - posReceptorError2.getY())
                    / (posTirador.getX() - posReceptorError2.getX());
            double c2 = a2 * posTirador.getX() - posTirador.getY();

            double distPeligro2 = Math.abs(a2 * rival.getX() + rival.getY() + c2)
                    / Math.sqrt(a2 * a2 + 1);

            double distTiradorReceptorConError = posTirador.distancia(posReceptorError1);

            // Revisar si esta forma de determinar que el rival puede cortar la recta del pase entre
            // tirador o receptor
            if (  rival.distancia(posReceptor) < 5 ||
                    rival.distancia(posTirador) < 5 ||
                    posReceptor.distancia(posTirador) * 0.75 > rival.distancia(posReceptor)) { // 1.25
                // Estas condiciones
                if (distPeligro1 < distTiradorReceptorConError) {
                    return false;
                }
                if (distPeligro2 < distTiradorReceptorConError) {
                    return false;
                }
            }
        }

        return true;
    }




    void pasarSiEnDefensa()
    {
        // En defensa busco si tengo un pase seguro, lo mas adelante posible.

        boolean porBajo = false;
        double distancia = 1000.0;
        Grosso grossoCercano = Grosso.Ninguno;

        for (int i = 0; i < 11; i++) {
            Posicion pos = situacionPartido().misJugadores()[i];
            if (tactica.getSectorPosicion(pos) != Sector.Defensa && esGrossoDisponible(getGrosso(i))
                    && esPasePorBajoSeguro(situacionPartido().balon(), getGrosso(i))) {
                double d = situacionPartido().balon().distancia(pos);
                // Por ahora establezco una distancia minima, para evitar que dos jugadores se peguen
                // y se den pases entre si muy cerca
                if (d > 10 && distancia > d) {
                    distancia = d;
                    grossoCercano = getGrosso(i);
                    porBajo = true;
                }
            }
        }


        if (grossoCercano == Grosso.Ninguno)
        {
            // No tengo pase seguro
            // Voy a buscar los jugadores mas desmarcados entre quienes esten en el mediocampo
            double puntos = -1000;
            for (int i = 0; i < 11; i++) {
                Posicion pos = situacionPartido().misJugadores()[i];
                if (tactica.getSectorPosicion(pos) != Sector.Defensa ) {
                    double d = situacionPartido().balon().distancia(pos);
                    
                    // Invento una puntuacion, la idea es que de mas chances a los que esten mas desmarcados
                    // Un componente menor premia a los mas cercanos

                    double puntosLocal = tactica.iteracionesMarcadorCercano(getGrosso(i))*2 /*- d*2*/;

                    // Por ahora establezco una distancia minima, para evitar que dos jugadores se peguen
                    // y se den pases entre si muy cerca
                    if (d > 10 && puntos < puntosLocal) {
                        puntos = puntosLocal;
                        grossoCercano = getGrosso(i);
                    }
                }
            }
        }

        darPase(grossoCercano, porBajo);


    }


    void pasarSiEnMedioOAtaque()
    {
        // En defensa busco si tengo un pase seguro, lo mas adelante posible.

        boolean porBajo = false;
        double distancia = 1000.0;
        Grosso grossoCercano = Grosso.Ninguno;

        for (int i = 0; i < 11; i++) {
            Posicion pos = situacionPartido().misJugadores()[i];
            if (tactica.getSectorPosicion(pos) != Sector.Defensa && esGrossoDisponible(getGrosso(i))
                    && esPasePorBajoSeguro(situacionPartido().balon(), getGrosso(i))) {

                double d = pos.distancia(Constantes.centroArcoSup);
                //double d = situacionPartido().balon().distancia(pos);
                // Por ahora establezco una distancia minima, para evitar que dos jugadores se peguen
                // y se den pases entre si muy cerca
                if (d > 10 && distancia > d) {
                    distancia = d;
                    grossoCercano = getGrosso(i);
                    porBajo = true;
                }
            }
        }


        if (grossoCercano == Grosso.Ninguno)
        {
            // No tengo pase seguro
            // Voy a buscar los jugadores mas desmarcados entre quienes esten en el mediocampo o en ataque
            double puntos = -1000;
            for (int i = 0; i < 11; i++) {
                Posicion pos = situacionPartido().misJugadores()[i];
                if (tactica.getSectorPosicion(pos) != Sector.Defensa) {
                    double dArco = situacionPartido().balon().distancia(Constantes.centroArcoSup);
                    double d = situacionPartido().balon().distancia(pos);

                    // TODO: componente por angulo de tiro

                    // Invento una puntuacion, la idea es que de mas chances a los que esten mas desmarcados
                    // Un componente menor premia a los mas cercanos

                    double puntosLocal = tactica.iteracionesMarcadorCercano(getGrosso(i))*2 - dArco;

                    // Por ahora establezco una distancia minima, para evitar juadores muy cerca del arco
                    // TODO: minimo de desmarcado??
                    if (d > 5 && puntos < puntosLocal) {
                        puntos = puntosLocal;
                        grossoCercano = getGrosso(i);
                    }
                }
            }
        }

        darPase(grossoCercano, porBajo);


    }

    void pasar() {
        // Reservo los que le pueden pegar a la pelota
        // De paso me queda facil despues para identificar los otros jugadores
        for (int i : situacionPartido().puedenRematar()) {
            // Acordarse de siempre preguntar si el grosso esta disponible, si no tiene ordenes anteriores
            if (esGrossoDisponible(getGrosso(i))) {
                // Los marco como usados de antemano
                MarcarGrossoUtilizado(getGrosso(i));
            }
        }


        switch (tactica.sectorActual)
        {
            case Defensa:
                pasarSiEnDefensa();
                break;
            case Ataque:
                pasarSiEnMedioOAtaque();
                break;
            case Medio:
                pasarSiEnMedioOAtaque();
                break;
        }

    }


    void darPase(Grosso grossoCercano, boolean porBajo) {
        if (grossoCercano != Grosso.Ninguno)
        {
            for (int i : situacionPartido().puedenRematar()) {
                if (i != Grosso.Rava.ordinal()) {

                    double anguloVertical = porBajo ? 0 : 40;
                    Posicion destino = situacionPartido().misJugadores()[grossoCercano.ordinal()];

                    // Si es pase por alto busquemos desmarcar al jugador
                    if (!porBajo)
                    {
                        // REVISAAAAR
                   // System.out.println("antes" + destino);
                   //     destino = destino.moverAngulo(destino.angulo(Constantes.centroArcoSup)*2, 10);
                    //System.out.println("despues" + destino);
                        // TODO: chequear mejor esto, que realmente se mueva a una parte desmarcada,
                        // quizas un for que busque la mejor posicion ???
                        int rivales[] = tactica.rivalesCercanos(destino, 15);
                        if (rivales.length > 0)
                        {
                            Posicion rival = situacionPartido().rivales()[rivales[0]];
                            double angulo = destino.angulo(rival);
                            destino = destino.moverAngulo(angulo + Math.PI, 0.1);

                        }
                    }

                    // Calculamos la fuerza
                    double fuerzaPase = calcularFuerzaPase(tactica.getGrosso(i), grossoCercano, destino, anguloVertical);

                    tactica.comandos.add(new ComandoGolpearBalon(i, destino,
                            fuerzaPase, anguloVertical));
                    tactica.grossoUltimoPase = getGrosso(i);
                    tactica.receptorUltimoPase = getGrosso(i);
                    MarcarGrossoUtilizado(tactica.grossoUltimoPase);
                }
            }
        }
    }

}
